﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using System.Collections;

namespace AppDemo
{
    /// <summary>
    /// Interaction logic for Window6.xaml
    /// </summary>
    public partial class Window6 : Window
    {
        public Window6()
        {
            InitializeComponent();
            int count = 800;
            List<string> list1 = new List<string>();
            List<string> list2 = new List<string>();
            List<string> list3 = new List<string>(count);
            for (int i = 0; i < count; i++)
            {
               list1.Add("list" + i);
                list2.Add("list" + i);
                list3.Add("list" + i);
            }
           box1.ItemsSource = list1;
            box2.ItemsSource = list2;
            box3.ItemsSource = list3;
        }

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            GC.Collect();
            GC.WaitForPendingFinalizers();
            GC.Collect();
        }
    }

    public class VisualPanel : FrameworkElement
    {
        protected VisualCollection Children { get; set; }

        public VisualPanel()
        {
            Children = new VisualCollection(this);
        }

        protected override int VisualChildrenCount
        {
            get
            {
                return Children.Count;
            }
        }

        protected override Visual GetVisualChild(int index)
        {
            return Children[index];
        }
    }

    public class VisualItemsControl : VisualPanel
    {
        public VisualItemsControl()
        {
            this.Loaded += new RoutedEventHandler(VisualItemsControl_Loaded);
        }

        protected ScrollViewer viewer;
        void VisualItemsControl_Loaded(object sender, RoutedEventArgs e)
        {
            viewer = this.Parent as ScrollViewer;
            viewer.ScrollChanged += new ScrollChangedEventHandler(viewer_ScrollChanged);
            Reflesh();
            this.Loaded -= VisualItemsControl_Loaded;
        }

        protected virtual int GetDisplayIndex()
        {
            if (viewer != null)
            {
                return (int)(viewer.VerticalOffset / this.ChildHeight);
            }
            return 0;
        }

        protected virtual int GetDisplayCount()
        {
            if (viewer != null)
            {
                return (int)Math.Ceiling(viewer.RenderSize.Height / this.ChildHeight);
            }
            return 0;
        }

        void viewer_ScrollChanged(object sender, ScrollChangedEventArgs e)
        {
            Reflesh();
        }

        public double ChildHeight { get; set; }

        private void Reflesh()
        {
            
            var index = GetDisplayIndex();
            var count = GetDisplayCount();
            
                if (Children.Count == 0)
                {
                    DrawingVisual dv = new DrawingVisual();

                    Children.Add(dv);
                }
        
            var dv2 = Children[0] as DrawingVisual;
            var dc = dv2.RenderOpen();
            var typeface = new Typeface("STLiti");
            for (int i = 0; i < count; i++)
            {
                var textFormat = new FormattedText(
                ItemsSource[i + index].ToString(), System.Globalization.CultureInfo.CurrentCulture,
                FlowDirection.LeftToRight,
                typeface,
                ChildHeight,
                Brushes.Black);
                textFormat.TextAlignment = TextAlignment.Left;
                //dc.DrawRectangle(Brushes.Red,null,new Rect(0,ChildHeight * (i + index),100,ChildHeight));
               dc.DrawText(textFormat, new Point(0, ChildHeight * (i + index)));
                //textFormat = null;
            }
            dc.Close();

            //for (int i = 0; i < count; i++)
            //{

            //    var tb = Children[i] as DrawingVisual;
            //    var dc = tb.RenderOpen();
            //    var textFormat = new FormattedText(
            //    ItemsSource[i + index].ToString(), System.Globalization.CultureInfo.CurrentCulture,
            //    FlowDirection.LeftToRight,
            //    new Typeface("STLiti"),
            //    ChildHeight,
            //    Brushes.Black);
            //    textFormat.TextAlignment = TextAlignment.Left;
            //    dc.DrawText(textFormat,new Point(0, ChildHeight * (i + index)));

            //    //dc.DrawRectangle(Brushes.Red, null, new Rect(0, ChildHeight * (i + index), 100, ChildHeight));
            //    dc.Close();
            //}


            if (this.DesiredSize.Height == 0)
            {
                this.InvalidateMeasure();
            }
        }

       

        protected double height = 15;


        public IList ItemsSource
        {
            get { return (IList)GetValue(ItemsSourceProperty); }
            set { SetValue(ItemsSourceProperty, value); }
        }

        public static readonly DependencyProperty ItemsSourceProperty =
            DependencyProperty.Register("ItemsSource", typeof(IList), typeof(VisualItemsControl),
                                        new FrameworkPropertyMetadata(default(IList)));

    }

    public class VisualListBox : VisualItemsControl
    {
        public VisualListBox()
        {
            ChildHeight = 15;
        }

        protected override Size MeasureOverride(Size availableSize)
        {
            Size desiredSize = new Size();
            desiredSize.Width = availableSize.Width;
            availableSize.Height = Double.PositiveInfinity;
            var count = GetDisplayCount();
            if (count > 0)
            {
                desiredSize.Height = Convert.ToDouble(ItemsSource.Count * ChildHeight);
            }
            return desiredSize;
        }

    }

    public class ElementlPanel : FrameworkElement
    {
        protected UIElementCollection Children {get;set;}

        public ElementlPanel()
        {
            Children = new UIElementCollection(this, this);
        }

        protected override int VisualChildrenCount
        {
            get
            {
                return Children.Count;
            }
        }

        protected override Visual GetVisualChild(int index)
        {
            return Children[index];
        }
    }

    public class ElementItemsControl : ElementlPanel
    {
        public ElementItemsControl()
        {
            this.Loaded += new RoutedEventHandler(VisualItemsControl_Loaded);
        }

        protected ScrollViewer viewer;
        void VisualItemsControl_Loaded(object sender, RoutedEventArgs e)
        {
            viewer = this.Parent as ScrollViewer;
            viewer.ScrollChanged += new ScrollChangedEventHandler(viewer_ScrollChanged);
            Reflesh();
            this.Loaded -= VisualItemsControl_Loaded;
        }

        protected virtual int GetDisplayIndex()
        {
            if (viewer != null)
            {
                return (int)(viewer.VerticalOffset / height);
            }
            return 0;
        }

        protected double height = 15;

        protected virtual int GetDisplayCount()
        {
            if (viewer != null)
            {
                return (int)Math.Ceiling(viewer.RenderSize.Height / height);
            }
            return 0;
        }

        void viewer_ScrollChanged(object sender, ScrollChangedEventArgs e)
        {
            Reflesh();
        }

        private void Reflesh()
        {
            var index = GetDisplayIndex();
            var count = GetDisplayCount();
            for (int i = Children.Count; i < count; i++)
            {
                Children.Add(new TextBlock());
            }
            for (int i = 0; i < count; i++)
            {

                var tb = Children[i] as TextBlock;
                if (tb != null)
                {
                    Console.WriteLine(ItemsSource[i + index].ToString());
                    tb.Text = ItemsSource[i + index].ToString();
                }
            }
            this.InvalidateArrange();
        }

        public IList ItemsSource
        {
            get { return (IList)GetValue(ItemsSourceProperty); }
            set { SetValue(ItemsSourceProperty, value); }
        }

        public static readonly DependencyProperty ItemsSourceProperty =
            DependencyProperty.Register("ItemsSource", typeof(IList), typeof(ElementItemsControl),
                                        new FrameworkPropertyMetadata(default(IList)));

    }

  

    public class ElementListBox : ElementItemsControl
    {
        public ElementListBox()
        {
        }

        protected override Size ArrangeOverride(Size finalSize)
        {
            if (Children.Count > 0)
            {
                var index = GetDisplayIndex();
                var size = new Size();
                var count = GetDisplayCount();
                for (int i = 0; i < count; i++)
                {
                    size = Children[i].DesiredSize;
                    Children[i].Arrange(new Rect(new Point(0, size.Height * (i + index)), size));
                }
            }
            return finalSize;
        }

        protected override Size MeasureOverride(Size availableSize)
        {
            Size desiredSize = new Size();
            desiredSize.Width = availableSize.Width;
            availableSize.Height = Double.PositiveInfinity;
            var count = GetDisplayCount();
            if (count > 0)
            {
                for (int i = 0; i < count; i++)
                {
                    Children[i].Measure(availableSize);
                }
                var internalheight = Children[0].DesiredSize.Height;
                desiredSize.Height = Convert.ToDouble(ItemsSource.Count * internalheight);
                height = internalheight;
            }
            return desiredSize;
        }

    }
}
